package GestorUsuarios;

/**
 * @file UsuarioDAO.java
 * @brief Implementa la clase UsuarioDAO
 * 
 * Implementa la clase UsuarioDAO usada para manejar la información de
 * los usuarios del sistema en la base de datos.
 * 
 * @author Víctor Martínez Gómez
 * @version 01.04
 * 
 */

import Controlador.UsuariosDisponibles;
import java.io.IOException;
import java.security.NoSuchAlgorithmException;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;

import Servicios.Conexion;


/**
 * @class UsuarioDAO
 * 
 * @brief Se encarga de realizar las operaciones para manejar la información de
 * 		  los usuarios del sistema en la base de datos.
 * 
 *        Se encarga de realizar las operaciones para manejar la información de
 *		  los usuarios del sistema. Permite realizar búsquedas, añadirlos a la
 *		  base de datos, etc.
 * 
 */

public class UsuarioDAO {

	/**
	 * @brief Cadenas relacionadas con el estado
	 */
	private static final String ESTADO_ACTIVO = "a";
	private static final String ESTADO_BAJA_TEMPORAL = "b";
	private static final String ESTADO_BAJA_DEFINITIVA = "d";
	/**
	 * @brief Cadenas relacionadas con el género
	 */
	private static final String GENERO_MASCULINO = "m";
	private static final String GENERO_FEMENINO = "f";
	/**
	 * @brief Cadenas relacionadas con el tipo de usuario
	 */
	private static final String TIPO_PACIENTE = "p";
	private static final String TIPO_MEDICO = "m";
	private static final String TIPO_GESTOR = "g";
	private static final String TIPO_FARMACEUTICO = "f";
        private static final String TIPO_TECNICO = "t";
	
	/**
	 * @brief Agrega el objeto Usuario la BD
	 * @param usuario Usuario a agregar
	 * @throws ClassNotFoundException, IOException, SQLException, IDException, NoSuchAlgorithmException 
	 */
	public static void add(Usuario usuario) throws SQLException, IOException, ClassNotFoundException, IDException, NoSuchAlgorithmException {
		String genero;
		String estado;
		String tipo;
                String observaciones;
		
		if(usuario.getEstado()==EstadoUsuario.ACTIVO)
			estado = ESTADO_ACTIVO;
		else if(usuario.getEstado()==EstadoUsuario.BAJA_TEMPORAL)
				estado = ESTADO_BAJA_TEMPORAL;
		else estado = ESTADO_BAJA_DEFINITIVA;
		
		if(usuario.getGenero()==GeneroUsuario.MASCULINO)
			genero = GENERO_MASCULINO;
		else
			genero = GENERO_FEMENINO;
		
		if(usuario.getTipo()==TipoUsuario.PACIENTE)
			tipo = TIPO_PACIENTE;
		else if(usuario.getTipo()==TipoUsuario.MEDICO)
			tipo = TIPO_MEDICO;
		else if(usuario.getTipo()==TipoUsuario.GESTOR)
			tipo = TIPO_GESTOR;
		else if(usuario.getTipo()==TipoUsuario.FARMACEUTICO)
                    tipo = TIPO_FARMACEUTICO;
                else
                    tipo = TIPO_TECNICO;
		
		DateFormat formatoFecha = new SimpleDateFormat("yyyy-MM-dd");

                if (usuario.getObservaciones() != null)
                    observaciones = "\'"+usuario.getObservaciones()+"\'";
                else
                    observaciones = "NULL";

		Conexion.conectar();
		Conexion.actualizar("INSERT Usuario(nombre,dniPasaporte,apellidos,fechaNacimiento,genero," +
				"correo,telefonoMovil,login,password,estado,tipoUsuario,observaciones) VALUES (\'"+usuario.getNombre()+
				"\', \'"+ usuario.getDniPasaporte() +
				"\', \'"+ usuario.getApellidos() +
				"\', \'"+ formatoFecha.format(usuario.getFechaNacimiento()) +
				"\', \'"+ genero +
				"\', \'"+ usuario.getCorreo() +
				"\', \'"+ usuario.getTelefonoMovil() +
				"\', \'"+ usuario.getLogin() +
				"\', \'"+ usuario.getPassword() +
				"\', \'"+ estado +
                                "\', \'"+ tipo +
				"\', "+ observaciones  + ");");
		// Buscamos por login, que es único
		Usuario[] usuario_bd = get(null, usuario.getLogin(), null, null, null, null);
		Conexion.desconectar();
		// Establecemos el id asignado en la base de datos
		if(usuario_bd==null) {
			throw new IDException();
		}
		usuario.setIdUsuario(usuario_bd[0].getIdUsuario());
	}
	
	/**
	 * @brief Obtiene la instancia de Usuario con el id indicado
	 * @param id Id del usuario a buscar
	 * @return El objeto Usuario obtenido
	 * @throws ClassNotFoundException, IOException, SQLException, NoSuchAlgorithmException 
	 */
	public static Usuario get(int id) throws SQLException, IOException, ClassNotFoundException, NoSuchAlgorithmException {
		Usuario usuario;
		Conexion.conectar();
		ResultSet tabla = Conexion.consultar("SELECT * FROM Usuario WHERE Usuario.idUsuario = "+ id +";");
		if(tabla.next()) { // Encontrado
			String string_genero = tabla.getString("genero");
			GeneroUsuario genero;
			if(string_genero.equals(GENERO_MASCULINO))
				genero = GeneroUsuario.MASCULINO;
			else 
				genero = GeneroUsuario.FEMENINO;
			
			String string_estado = tabla.getString("estado");
			EstadoUsuario estado;
			if(string_estado.equals(ESTADO_ACTIVO))
				estado = EstadoUsuario.ACTIVO;
			else if (string_estado.equals(ESTADO_BAJA_TEMPORAL))
				estado = EstadoUsuario.BAJA_TEMPORAL;
			else estado = EstadoUsuario.BAJA_DEFINITIVA;
			
			String string_tipo = tabla.getString("tipoUsuario");
			TipoUsuario tipo;
			if(string_tipo.equals(TIPO_PACIENTE))
				tipo = TipoUsuario.PACIENTE;
			else if (string_tipo.equals(TIPO_MEDICO))
				tipo = TipoUsuario.MEDICO;
			else if (string_tipo.equals(TIPO_GESTOR))
				tipo = TipoUsuario.GESTOR;
			else if(string_tipo.equals(TIPO_FARMACEUTICO))
                                tipo = TipoUsuario.FARMACEUTICO;
                        else
                                tipo = TipoUsuario.TECNICOPRUEBAS;

                        
                        usuario = new Usuario(tabla.getInt("idUsuario"), tabla.getString("dniPasaporte"),
					tabla.getString("nombre"), tabla.getString("apellidos"), tabla.getDate("fechaNacimiento"),
					genero, tabla.getString("correo"), tabla.getInt("telefonoMovil"),
					tabla.getString("login"), tabla.getString("password"), estado, tipo,tabla.getString("observaciones"));
		} else {
			usuario = null;
		}
		Conexion.desconectar();
		return usuario;
	}
	
	/**
	 * @brief Obtiene las instancias Usuario que coincidan con los paráametros no nulos 
	 * pasados como argumento. Si hay algún parámetro nulo, este no sera tenido en cuenta
	 * para la búsqueda.
	 * @param dniPasaporte El dni o pasaporte a buscar
	 * @param login El login a buscar
	 * @param nombre El nombre a buscar
	 * @param apellidos Los apellidos a buscar
	 * @param tipousuario Tipo de usuario a buscar
	 * @param estado Estado del usuario a buscar
	 * @return Un vector de objetos Usuario obtenidos
	 * @throws ClassNotFoundException, IOException, SQLException,NoSuchAlgorithmException 
	 */
	public static Usuario[] get(String dniPasaporte, String login, String nombre, String apellidos, TipoUsuario tipousuario, EstadoUsuario estado) throws SQLException, IOException, ClassNotFoundException, NoSuchAlgorithmException {
		Usuario [] usuarios = null;
		Conexion.conectar();
		
		String parte_sel = "WHERE ";
		if(dniPasaporte!=null)
			parte_sel += "dniPasaporte = \'"+ dniPasaporte +"\' AND ";
		if(login!=null)
			parte_sel += "login = \'"+ login +"\' AND ";
		if(nombre!=null)
			parte_sel += "nombre = \'"+ nombre +"\' AND ";
		if(apellidos!=null)
			parte_sel += "apellidos = \'"+ apellidos +"\' AND ";
		if(tipousuario!=null)
			if(tipousuario==TipoUsuario.PACIENTE)
				parte_sel += "tipoUsuario = \'"+ TIPO_PACIENTE +"\' AND ";
			else if(tipousuario==TipoUsuario.MEDICO)
				parte_sel += "tipoUsuario = \'"+ TIPO_MEDICO +"\' AND ";
			else if(tipousuario==TipoUsuario.GESTOR)
				parte_sel += "tipoUsuario = \'"+ TIPO_GESTOR +"\' AND ";
			else if(tipousuario==TipoUsuario.FARMACEUTICO)
                            parte_sel += "tipoUsuario = \'"+ TIPO_FARMACEUTICO +"\' AND ";
                        else parte_sel += "tipoUsuario = \'"+ TIPO_TECNICO +"\' AND ";
                
		if(estado!=null)
			if(estado==EstadoUsuario.ACTIVO)
				parte_sel += "estado = \'"+ ESTADO_ACTIVO +"\'  AND ";
			else if(estado==EstadoUsuario.BAJA_TEMPORAL)
				parte_sel += "estado = \'"+ ESTADO_BAJA_TEMPORAL +"\'  AND ";
			else parte_sel += "estado = \'"+ ESTADO_BAJA_DEFINITIVA +"\'  AND ";
		
		// Sustituimos coma final, por punto y coma
		parte_sel = parte_sel.substring(0, parte_sel.length()-4)+";";
		
		ResultSet tabla = Conexion.consultar("SELECT * FROM Usuario " + parte_sel);
		
		ArrayList<Usuario> list_usuarios = new ArrayList<Usuario>();
		while(tabla.next()) {
			String string_genero = tabla.getString("genero");
			GeneroUsuario genero;
			if(string_genero.equals(GENERO_MASCULINO))
				genero = GeneroUsuario.MASCULINO;
			else 
				genero = GeneroUsuario.FEMENINO;
			
			String string_estado = tabla.getString("estado");
			EstadoUsuario estado_usuario;
			if(string_estado.equals(ESTADO_ACTIVO))
				estado_usuario = EstadoUsuario.ACTIVO;
			else if (string_estado.equals(ESTADO_BAJA_TEMPORAL))
				estado_usuario = EstadoUsuario.BAJA_TEMPORAL;
			else estado_usuario = EstadoUsuario.BAJA_DEFINITIVA;
			
			String string_tipo = tabla.getString("tipoUsuario");
			TipoUsuario tipo_usuario;
			if(string_tipo.equals(TIPO_PACIENTE))
				tipo_usuario = TipoUsuario.PACIENTE;
			else if (string_tipo.equals(TIPO_MEDICO))
				tipo_usuario = TipoUsuario.MEDICO;
			else if (string_tipo.equals(TIPO_GESTOR))
				tipo_usuario = TipoUsuario.GESTOR;
			else if (string_tipo.equals(TIPO_FARMACEUTICO))
				tipo_usuario = TipoUsuario.FARMACEUTICO;
                        else
                                tipo_usuario = TipoUsuario.TECNICOPRUEBAS;

			list_usuarios.add(new Usuario(tabla.getInt("idUsuario"), tabla.getString("dniPasaporte"),
					tabla.getString("nombre"), tabla.getString("apellidos"), tabla.getDate("fechaNacimiento"),
					genero, tabla.getString("correo"), tabla.getInt("telefonoMovil"),
					tabla.getString("login"), tabla.getString("password"), estado_usuario,tipo_usuario,
                                        tabla.getString("observaciones")));
		}
		
		Conexion.desconectar();
		
		
		if(list_usuarios.size()>0) {
			usuarios = new Usuario[list_usuarios.size()];
			list_usuarios.toArray(usuarios);
			return usuarios;
		}
		else return null;
	}
	
	/**
	 * @brief Obtiene los medicos que no tienen citas que se solapen con la hora
	 * de inicio y la hora fin.
	 * @param inicio Hora de inicio
	 * @param fin Hora de fin
	 * @return Un vector de objetos Usuario obtenidos
	 * @throws ClassNotFoundException, IOException, SQLException,NoSuchAlgorithmException 
	 */
        
	public static Medico[] getMedicosDisponibles(Date inicio, Date fin) throws SQLException, IOException, ClassNotFoundException, NoSuchAlgorithmException {
		Medico [] medicos = null;
		DateFormat formatoFecha = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		
		Conexion.conectar();
		
		Calendar calendario = Calendar.getInstance();
		calendario.setTime(inicio);
		int diaSemana = calendario.get(Calendar.DAY_OF_WEEK);
		
		String stringDiaSemana="";
		if(diaSemana==2)
			stringDiaSemana = "l";
		else if(diaSemana==3)
			stringDiaSemana = "m";
		else if(diaSemana==4)
			stringDiaSemana = "x";
		else if(diaSemana==5)
			stringDiaSemana = "j";
		else if(diaSemana==6)
			stringDiaSemana = "v";
		else if(diaSemana==0)
			stringDiaSemana = "s";
		else if(diaSemana==1)
			stringDiaSemana = "d";
		
		
		
		String horaInicio = "" + calendario.get(Calendar.HOUR_OF_DAY);

		ResultSet tabla = Conexion.consultar("SELECT * FROM Usuario u WHERE u.tipoUsuario='m' AND u.estado='a' AND NOT EXISTS (SELECT * FROM Cita c WHERE c.idMedico=u.idUsuario AND c.estado='p' AND (\'" 
				+formatoFecha.format(inicio)+"\' BETWEEN c.fechaCita AND c.fechaFinalizacion OR \'"+formatoFecha.format(fin)+"\' BETWEEN c.fechaCita AND c.fechaFinalizacion OR c.fechaCita BETWEEN \'"+
				formatoFecha.format(inicio)+"\' AND \'"+formatoFecha.format(fin)+"\' OR c.fechaFinalizacion BETWEEN \'"+formatoFecha.format(inicio)+"\' AND \'"+formatoFecha.format(fin)+"\'))" +
						" AND EXISTS (SELECT * FROM HoraTrabajo h, trabaja t WHERE h.diaSemana=\'"+stringDiaSemana+"\' AND h.horaInicio=\'"+horaInicio+"\' AND h.idHoraTrabajo=t.idHoraTrabajo AND t.idUsuario=u.idUsuario );");
		
		ArrayList<Medico> list_medicos = new ArrayList<Medico>();
		while(tabla.next()) {
			String string_genero = tabla.getString("genero");
			GeneroUsuario genero;
			if(string_genero.equals(GENERO_MASCULINO))
				genero = GeneroUsuario.MASCULINO;
			else 
				genero = GeneroUsuario.FEMENINO;
			
			String string_estado = tabla.getString("estado");
			EstadoUsuario estado_usuario;
			if(string_estado.equals(ESTADO_ACTIVO))
				estado_usuario = EstadoUsuario.ACTIVO;
			else if (string_estado.equals(ESTADO_BAJA_TEMPORAL))
				estado_usuario = EstadoUsuario.BAJA_TEMPORAL;
			else estado_usuario = EstadoUsuario.BAJA_DEFINITIVA;
			
			
			list_medicos.add(new Medico(tabla.getInt("idUsuario"), tabla.getString("dniPasaporte"),
					tabla.getString("nombre"), tabla.getString("apellidos"), tabla.getDate("fechaNacimiento"),
					genero, tabla.getString("correo"), tabla.getInt("telefonoMovil"),
					tabla.getString("login"), tabla.getString("password"), estado_usuario,null));
		}
		
		Conexion.desconectar();
		
		
		if(list_medicos.size()>0) {
			medicos = new Medico[list_medicos.size()];
			list_medicos.toArray(medicos);
			return medicos;
		}
		else return null;
	}


         /**
         * Encuentra los tecnico disponibles para realizar pruebas medicas entre las
         * fechas indicadas. Si la fin es nulo dare solo las fechas disponibles de ese dia.
         * @param inicio Fecha inicio
         * @param fin Fecha fin
         * @return Array de usuarios disponibles
         * @throws ClassNotFoundException, IOException, SQLException, NoSuchAlgorithmException
         */
        public static UsuariosDisponibles[] getMedicosDisponiblesOptimizado(Date inicio, Date fin)
                throws SQLException, IOException, ClassNotFoundException, NoSuchAlgorithmException
        {
            DateFormat formatoFecha = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            UsuariosDisponibles res[] = null;
            ArrayList<UsuariosDisponibles> d  = new ArrayList<UsuariosDisponibles>();
            Calendar calendario = Calendar.getInstance();
            calendario.setTime(inicio);
            int diaSemana;
            String stringDiaSemana="";
            String horaInicio;
            ResultSet tabla;

            if ( fin == null ) { //ponemos como fecha final el fin de dia 23:59:00
                Calendar aux ;
                aux = Calendar.getInstance();
                aux.setTime(inicio);
                aux.set(Calendar.HOUR_OF_DAY,23);
                aux.set(Calendar.MINUTE, 59);
                fin = aux.getTime();
            }

            Conexion.conectar();
            for ( int i=0 ; calendario.getTime().before(fin) ; i++)
            {
                //System.out.println("Dia semana "+stringDiaSemana);
                //System.out.println(formatoFecha.format(calendario.getTime()));

                //Vemos los datos previos
                diaSemana = calendario.get(Calendar.DAY_OF_WEEK);
                if(diaSemana==Calendar.MONDAY)
                    stringDiaSemana = "l";
                else if(diaSemana==Calendar.TUESDAY)
                    stringDiaSemana = "m";
                else if(diaSemana==Calendar.WEDNESDAY)
                    stringDiaSemana = "x";
                else if(diaSemana==Calendar.THURSDAY)
                    stringDiaSemana = "j";
                else if(diaSemana==Calendar.FRIDAY)
                    stringDiaSemana = "v";
                else if(diaSemana==Calendar.SATURDAY)
                    stringDiaSemana = "s";
                else if(diaSemana==Calendar.SUNDAY)
                    stringDiaSemana = "d";

                horaInicio = "" + calendario.get(Calendar.HOUR_OF_DAY);

                Date fechaInicio = calendario.getTime();
                Calendar cal_temp = Calendar.getInstance();
                cal_temp.setTime(fechaInicio);
                cal_temp.add(Calendar.MINUTE, 10);
                Date fechaFin = cal_temp.getTime();

                //Realizamos la consulta
		tabla = Conexion.consultar("SELECT * FROM Usuario u WHERE u.tipoUsuario='m' AND u.estado='a' AND NOT EXISTS (SELECT * FROM Cita c WHERE c.idMedico=u.idUsuario AND c.estado='p' AND (\'"
				+formatoFecha.format(fechaInicio)+"\' BETWEEN c.fechaCita AND c.fechaFinalizacion OR \'"+formatoFecha.format(fechaFin)+"\' BETWEEN c.fechaCita AND c.fechaFinalizacion OR c.fechaCita BETWEEN \'"+
				formatoFecha.format(fechaInicio)+"\' AND \'"+formatoFecha.format(fechaFin)+"\' OR c.fechaFinalizacion BETWEEN \'"+formatoFecha.format(fechaInicio)+"\' AND \'"+formatoFecha.format(fechaFin)+"\'))" +
						" AND EXISTS (SELECT * FROM HoraTrabajo h, trabaja t WHERE h.diaSemana=\'"+stringDiaSemana+"\' AND h.horaInicio=\'"+horaInicio+"\' AND h.idHoraTrabajo=t.idHoraTrabajo AND t.idUsuario=u.idUsuario );");


                d.add(new UsuariosDisponibles(fechaInicio,fechaFin));
                while (tabla.next()) {
                    (d.get(i)).setId(tabla.getInt("idUsuario"));
                }

                //añadimos 20 minutos del periodo entre prueba y prueba
                calendario.add(Calendar.MINUTE, 10);
            }//end for

            Conexion.desconectar();

            //devolvemos el resultados
            if(d.size()>0) {
                res = new UsuariosDisponibles[d.size()];
                d.toArray(res);
            }

            return res;
        }


	/**
	 * @brief Actualiza la información asociada al objeto Usuario
	 * @param usuario Usuario a actualizar
	 * @throws ClassNotFoundException, IOException, SQLException
	 */
	public static void update(Usuario usuario) throws SQLException, IOException, ClassNotFoundException {
		String genero;
		String estado;
		String tipo;
                String observaciones;
		
		if(usuario.getEstado()==EstadoUsuario.ACTIVO)
			estado = ESTADO_ACTIVO;
		else if(usuario.getEstado()==EstadoUsuario.BAJA_TEMPORAL)
				estado = ESTADO_BAJA_TEMPORAL;
		else estado = ESTADO_BAJA_DEFINITIVA;
		
		if(usuario.getGenero()==GeneroUsuario.MASCULINO)
			genero = GENERO_MASCULINO;
		else
			genero = GENERO_FEMENINO;
		
		if(usuario.getTipo()==TipoUsuario.PACIENTE)
			tipo = TIPO_PACIENTE;
		else if(usuario.getTipo()==TipoUsuario.MEDICO)
			tipo = TIPO_MEDICO;
		else if(usuario.getTipo()==TipoUsuario.GESTOR)
			tipo = TIPO_GESTOR;
		else if(usuario.getTipo()==TipoUsuario.FARMACEUTICO)
                        tipo = TIPO_FARMACEUTICO;
                else
                        tipo = TIPO_TECNICO;
		
		DateFormat formatoFecha = new SimpleDateFormat("yyyy-MM-dd");

                if (usuario.getObservaciones() != null)
                    observaciones = "\'"+usuario.getObservaciones()+"\'";
                else
                    observaciones = "NULL";
                
		Conexion.conectar();
		Conexion.actualizar("UPDATE Usuario SET nombre=\'"+usuario.getNombre()+
				"\', dniPasaporte = \'"+ usuario.getDniPasaporte() +
				"\', apellidos = \'"+ usuario.getApellidos() +
				"\', fechaNacimiento = \'"+ formatoFecha.format(usuario.getFechaNacimiento()) +
				"\', genero = \'"+ genero +
				"\', correo = \'"+ usuario.getCorreo() +
				"\', telefonoMovil = \'"+ usuario.getTelefonoMovil() +
				"\', login = \'"+ usuario.getLogin() +
				"\', password = \'"+ usuario.getPassword() +
				"\', estado = \'"+ estado +
				"\', tipoUsuario = \'"+ tipo +
				"\', observaciones = "+ observaciones +
                                " WHERE idUsuario="+usuario.getIdUsuario()+";");
		Conexion.desconectar();
	}
}